home *** CD-ROM | disk | FTP | other *** search
/ TOS Silver 2000 / TOS Silver 2000.iso / programm / MM2_DEV / S / MOS / FILEMANA.I < prev    next >
Encoding:
Text File  |  1991-04-09  |  33.9 KB  |  3 lines

  1. ⓪ IMPLEMENTATION MODULE FileManagement;⓪ (*$R-,Y+*)⓪ (*$H+*)⓪ ⓪ (*FROM InOut IMPORT WriteString, WriteLn, Read, WriteCard, WriteInt;*)⓪ ⓪ ⓪ (*  --------------------------------------------------------------------------⓪!*  System-Version: MOS 1.1⓪!*  --------------------------------------------------------------------------⓪!*  Version       : 1.01⓪!*  --------------------------------------------------------------------------⓪!*  Text-Version  : V#0262⓪!*  --------------------------------------------------------------------------⓪!*  Modul-Holder  : Manuel Chakravarty⓪!*  --------------------------------------------------------------------------⓪!*  Copyright August 1988 by Manuel Chakravarty⓪!*  Vertriebsrechte für ATARI ST unter MEGAMAX Modula-2⓪!*                  liegen bei Application Systems Heidelberg⓪!*  --------------------------------------------------------------------------⓪!*  MCH : Manuel Chakravarty⓪!*  DS  : Dirk Steins ⓪!*  --------------------------------------------------------------------------⓪!*  Datum    Autor  Version  Bemerkung (Arbeitsbericht)⓪!*⓪!*  07.08.88 MCH    V0.01    Erste Definitionen⓪!*  08.08.88 MCH    V0.01    'fileList' + 'insertFileInList'⓪!*  09.08.88 MCH    V0.01    Austesten der 'fileList'-Verwaltung + 'DeleteFiles'⓪!*  09.08.88 MCH    V0.02    Nochmal⓪!*  10.08.88 MCH    V0.02    'FormatDisk' (norm. SS und DS) + 'DeleteFiles'⓪!*  11.08.88 MCH    V0.02    'CopyFiles' läuft (Tra-Ra!)⓪!*  24.08.88 MCH    V0.03    'CountFilesAndDirs' extern⓪!*  25.08.88 MCH    V0.03    Geänderte Status-Verwaltung⓪!*  27.08.88 MCH    V0.03    'minExternalSpace' eingeführt.⓪!*  28.08.88 MCH    V0.04    'FileInformation' Def. + Imp.⓪!*  11.08.88 MCH    V0.04    Datum/Uhrzeit bleibt beim Kopieren erhalten⓪!*  03.09.89 MCH    V0.04    Fehlerbehandlung verbessert⓪!*  11.09.89 TT     V0.05    readIntoBuffer: Fehlerabfrage entfernt⓪!*  30.6.90  DS     V0.06    DestPath von Files wird bei geändertem Ordnername⓪!*                           jetzt korrekt geändert. Änderungen sind gekenn-⓪!*                           zeichnet mit %%.⓪!*  24.10.90 TT     V0.07    Doku im Def-Text korrigiert; FormatDrive mit⓪!*                           mit Directory.Drive-Werten definiert (Def-Text);⓪!*                           $H+ eingebaut⓪!*  10.11.90 TT     V0.07    $R-⓪!*  11.03.91 TT     V1.01    FileInformation berücksichtigt Ordner und kann⓪!*                           auch Zeit/Datum neu setzen.⓪!*  09.04.91 TT     V1.02    FormatDisk wertet 'drive' nun richtig aus (bisher⓪!*                           wurde bei 'drvA' LW B: formatiert.⓪!*  --------------------------------------------------------------------------⓪!*  Modul-Beschreibung:⓪!*⓪!*  Dieses Modul stellt Routinen für die Dateiverwaltung zur Verfügung.⓪!*  --------------------------------------------------------------------------⓪!*)⓪ ⓪ (*  -- Wie sieht es mit Datum und Zeit bei Ordnern aus??????⓪!*  -- Wird beim Namenskonflikt von Ordnern ein neuer Name angegeben, so muß⓪!*     der DestPath der Ordnerelemente entsprechend geändert werden.⓪!*     Behoben Dirk Steins⓪!*  -- Tritt bei 'flushBufferElem' während des Schreibens ein Fehler auf, so⓪!*     ist nicht gewährleistet, daß das File anständig geschlossen wird.⓪!*  -- Evtl. 'queryFileList' exportieren (z.B für Modul-Loading in der Shell).⓪!*)⓪ ⓪ ⓪ FROM SYSTEM IMPORT ADDRESS, TSIZE,⓪3ASSEMBLER, ADR;⓪ ⓪ FROM Storage IMPORT ALLOCATE, DEALLOCATE, MemAvail;⓪ ⓪ FROM Strings IMPORT Length, Concat, Append, Empty, Insert, Copy, StrEqual,⓪4Assign;⓪ ⓪ IMPORT Strings, FastStrings, FuncStrings;⓪ ⓪ FROM MOSGlobals IMPORT OutOfMemory, GeneralErr, fOK, fFileNotFound,⓪7fPathNotFound, fAccessDenied, fFileExists,⓪7fDiskFull, fIllegalCall, DriveStr, PathStr,⓪7FileStr;⓪ ⓪ FROM Clock IMPORT Time, Date;⓪ ⓪ FROM Directory IMPORT FileAttr, FileAttrSet, DirEntry,⓪6SetFileAttr, Delete, Rename, GetDirEntry,⓪6DirQuery, CreateDir, DeleteDir;⓪ ⓪ FROM FileNames IMPORT SplitPath;⓪ ⓪ FROM Files IMPORT File, Access, ReplaceMode,⓪2Create, Open, Close, SetDateTime, GetDateTime, State,⓪2GetStateMsg, ResetState, Remove;⓪ ⓪ FROM Binary IMPORT SeekMode,⓪3ReadBytes, WriteBytes, FileSize, Seek, FilePos;⓪ ⓪ FROM Lists IMPORT List, CreateList, DeleteList, RemoveEntry, AppendEntry,⓪2ResetList, NextEntry, PrevEntry, CurrentEntry, NoOfEntries;⓪ ⓪ FROM SysUtil0 IMPORT VarEqual;⓪ ⓪ ⓪ CONST   (*  MOS const.s  *)⓪ ⓪(noErrorTrap     = 6;⓪ ⓪((*  system call opcodes  *)⓪ ⓪(flopwr          = 9;⓪(flopfmt         = 10;⓪(protobt         = 18;⓪(⓪(xbios           = 14;⓪(⓪((*  misc  *)⓪(⓪(filesAndSubdirs = FileAttrSet {subdirAttr};⓪(⓪(⓪(minCopySpace    = 10L * 1024L;  (*  10k minimal  *)⓪(minExternalSpace= 30L * 1024L;  (*  30k minimal for other prog.s  *)⓪((* erweitert auf 30k für Pfadlisten *)⓪ ⓪ TYPE    ptrMaxStr       = POINTER TO ARRAY[0..32767] OF CHAR;⓪(str128          = ARRAY[0..127] OF CHAR;⓪(fileName        = ARRAY[0..11] OF CHAR;⓪(ptrCardinal     = POINTER TO CARDINAL;⓪(⓪(⓪ TYPE    statusRecord    = RECORD⓪<fileErrAlert: FileErrorAlertProc;⓪<⓪<showStatus  : FileOpStatusProc;⓪<noFiles     : CARDINAL;⓪:END;⓪(ptrStatusRecord = POINTER TO statusRecord;⓪(⓪((*  types for the copy buffer  *)⓪(⓪(copyBufferElem  = POINTER TO RECORD⓪<next    : copyBufferElem;   (*  NIL <=> not used  *)⓪<newPath : str128;⓪<isSubdir: BOOLEAN;⓪<date    : Date;             (*  of creation  *)⓪<time    : Time;             (*  of creation  *)⓪<seekPos : LONGCARD;         (*  append if > 0L  *)⓪<start   : ADDRESS;          (*  start of data  *)⓪<length  : LONGCARD;         (*  length of data  *)⓪:END;⓪(⓪(copyBuffer      = POINTER TO RECORD⓪<bottom,                     (*  first buffer elem *)⓪<next      : copyBufferElem; (*  next elem. to use *)⓪<length    : LONGCARD;       (*  buffer length  *)⓪<⓪<status    : statusRecord;⓪<⓪<feAlert   : FileExistsAlertProc;⓪<oldPathLen: CARDINAL;⓪<newPath   : str128;⓪<⓪<success   : BOOLEAN;        (*  FALSE ~ Error  *)⓪:END;⓪'⓪ ⓪ VAR     voidO : BOOLEAN;⓪(voidI : INTEGER;⓪(voidFN: fileName;⓪(void128: str128;⓪(⓪ ⓪ CONST   DebugInfo = FALSE;⓪ ⓪ (*$? DebugInfo:⓪ ⓪ PROCEDURE wLn (REF str: ARRAY OF CHAR);⓪ ⓪"BEGIN⓪$WriteString (str); WriteLn;⓪"END wLn;⓪ ⓪ PROCEDURE w (REF str: ARRAY OF CHAR);⓪ ⓪"BEGIN⓪$WriteString (str);⓪"END w;⓪ ⓪ PROCEDURE wc (c: LONGCARD);⓪ ⓪"BEGIN⓪$WriteCard (c, 6);⓪"END wc;⓪ ⓪ PROCEDURE wi (c: INTEGER);⓪ ⓪"BEGIN⓪$WriteInt (c, 6);⓪"END wi;⓪ ⓪ PROCEDURE wsiLn (REF str: ARRAY OF CHAR; i: INTEGER);⓪ ⓪"BEGIN⓪$w (str); wi (i); WriteLn;⓪"END wsiLn;⓪ ⓪ PROCEDURE wcsLn (l: LONGCARD; REF str: ARRAY OF CHAR);⓪ ⓪"BEGIN⓪$wc (l); wLn (str);⓪"END wcsLn;⓪"⓪ PROCEDURE wscLn (REF str: ARRAY OF CHAR; l: LONGCARD);⓪ ⓪"BEGIN⓪$w (str); wc (l); WriteLn;⓪"END wscLn;⓪"⓪ PROCEDURE Wait;⓪ ⓪"VAR ch: CHAR;⓪"⓪"BEGIN⓪$Read (ch);⓪"END Wait;⓪!*)⓪"⓪8(*  misc. proc.s  *)⓪8(*  ============  *)⓪ ⓪ PROCEDURE reportOutOfMemory;⓪ ⓪"(*$L-*)⓪"BEGIN⓪$ASSEMBLER⓪(TRAP    #noErrorTrap⓪(DC.W    OutOfMemory - $4000⓪$END;⓪"END reportOutOfMemory;⓪"(*$L=*)⓪"⓪ PROCEDURE reportPathFault;⓪ ⓪"(*$L-*)⓪"BEGIN⓪$ASSEMBLER⓪(TRAP    #noErrorTrap⓪(DC.W    GeneralErr - $C000⓪(ACZ     'FileManagement: Illegal path!'⓪(SYNC⓪$END;⓪"END reportPathFault;⓪"(*$L=*)⓪"⓪ ⓪ PROCEDURE isSubdir (attrs: FileAttrSet): BOOLEAN;⓪ ⓪"BEGIN⓪$RETURN subdirAttr IN attrs⓪"END isSubdir;⓪ ⓪ ⓪ PROCEDURE GetFileAttr (REF name  : ARRAY OF CHAR;⓪7VAR attr  : FileAttrSet;⓪7VAR result: INTEGER);⓪"⓪"VAR   entry: DirEntry;⓪"⓪"BEGIN⓪$GetDirEntry (name, entry, result);⓪&(* -> Directory.GetFileAttr geht nicht bei Subdirs. *)⓪$attr := entry.attr;⓪"END GetFileAttr;⓪ ⓪ PROCEDURE doShowStatus (    statusRecPtr: ptrStatusRecord;⓪<ioRes       : INTEGER;⓪8VAR stop        : BOOLEAN);⓪ ⓪"VAR   report,⓪(continue: BOOLEAN;⓪(⓪"BEGIN⓪$WITH statusRecPtr^ DO⓪$⓪&report := (ioRes = fFileNotFound) OR (ioRes = fPathNotFound)⓪0OR (ioRes = fAccessDenied) OR (ioRes = fDiskFull);⓪&continue := (ioRes = fOK) OR (ioRes = fFileNotFound)⓪2OR (ioRes = fPathNotFound) OR (ioRes = fAccessDenied)⓪2OR (ioRes = fFileExists);⓪$⓪&IF report THEN fileErrAlert (ioRes) END;⓪&stop := ~ continue;⓪$⓪&IF ~ stop THEN⓪(IF noFiles > 0 THEN DEC (noFiles) END;⓪(showStatus (noFiles, stop);⓪&END;⓪&⓪$END;⓪"END doShowStatus;⓪ ⓪ ⓪0(*  operations on the 'copyBuffer'  *)⓪0(*  ==============================  *)⓪0⓪ ⓪ (*  createCopyBuffer -- Alloc.s as much memory as possible and creates⓪!*                      a 'copyBuffer' with it.⓪!*                      'useAllMem = FALSE' means to use 2/5 of the largest⓪!*                      avaible mem. block, else the whole block is used.⓪!*                      'success = FALSE' means, not enough memory.⓪!*)⓪!⓪ PROCEDURE createCopyBuffer (VAR cb       : copyBuffer;⓪@useAllMem: BOOLEAN;⓪<VAR success  : BOOLEAN);⓪ ⓪"PROCEDURE memAvail (): LONGCARD;⓪"⓪$VAR res: LONGCARD;⓪"⓪$BEGIN⓪&IF useAllMem THEN⓪(res := MemAvail ();⓪(IF res < minExternalSpace THEN res := 0⓪(ELSE res := res - minExternalSpace END;⓪&ELSE⓪(res := MemAvail () * 2L DIV 5L;⓪(IF res < minExternalSpace THEN res := 0 END;⓪&END;⓪&⓪&res := res - res MOD 2L;          (*  make even  *)⓪&⓪&RETURN res⓪$END memAvail;⓪$⓪ ⓪"BEGIN⓪$success := (memAvail () >= minCopySpace );⓪$IF ~ success THEN RETURN END;⓪$⓪$NEW (cb);⓪$WITH cb^ DO⓪&length := memAvail ();       (*  take as much as possible  *)⓪&ALLOCATE (bottom, length);⓪&next := bottom;              (*  next elem. to use is the first elem.  *)⓪&bottom^.next := NIL;         (*  first elem. is not yet in use  *)⓪$END;⓪"END createCopyBuffer;⓪ ⓪ PROCEDURE deleteCopyBuffer (cb: copyBuffer);⓪ ⓪"BEGIN⓪$DEALLOCATE (cb^.bottom, 0L);⓪$DISPOSE (cb);⓪"END deleteCopyBuffer;⓪"⓪ ⓪ (*  bufAvail -- Determines the maximum amount of bytes, that are avaible⓪!*              in the 'cb'.⓪!*)⓪ ⓪ PROCEDURE bufAvail (cb: copyBuffer): LONGCARD;⓪ ⓪"BEGIN⓪$RETURN cb^.length - (LONGCARD (cb^.next) - LONGCARD (cb^.bottom))⓪+- SIZE (cb^.next^)⓪"END bufAvail;⓪"⓪ (*  flushCopyBuffer -- Writes the data in 'cb' to the destination.⓪!*)⓪ ⓪((* %% added 27.6.90 DS             *)⓪((* pc: short for PathChange     *)⓪ (*   The 'pcList' is the pathChangedList. In this list all path's⓪!*   which were changed during flushBuffer will be stored. ⓪!*   This Types and vars are global because the 'pcList' is initialised in⓪!*   the procedure 'copyFiles'. And it has to be global because otherwise⓪!*   some entries would be forgotten.⓪!*)⓪!⓪"TYPE    pcEntry         = RECORD⓪>oldPath,⓪>newPath     : str128;⓪<END;⓪*pcPtr           = POINTER TO pcEntry;⓪*⓪"VAR     pcList  : List;⓪ ⓪ PROCEDURE flushCopyBuffer (cb: copyBuffer);⓪ ⓪"VAR   elem : copyBufferElem;⓪(ioRes: INTEGER;⓪(f    : File;⓪(mode : ReplaceMode;⓪(path : str128;⓪(fn,⓪(orgFn,                  (* %% added 30.6.90 DS: is needed for the⓪A* pcList and the original pathname in it.⓪A*)⓪(oldFn: fileName;⓪(stop : BOOLEAN;⓪(⓪"PROCEDURE stateErr (): BOOLEAN;⓪$⓪$BEGIN⓪&ioRes := State (f);⓪&IF ioRes # fOK THEN ResetState (f) END;⓪&RETURN ioRes # fOK⓪$END stateErr;⓪$⓪((* %% added 27.6.90 DS *)⓪"PROCEDURE insertChangeEntry (VAR path : ARRAY OF CHAR;⓪?VAR old, new : ARRAY OF CHAR;⓪?start : CARDINAL) : BOOLEAN;⓪$(* inserts the newPath corresponding to oldPath in the ⓪%* pathList. If no oldPath is found a new entry is created.⓪%* Creating a new entry is the normal case due to changes in⓪%* development.⓪%*)⓪$VAR sPath : str128;⓪(pc    : pcPtr;⓪"BEGIN⓪$FastStrings.Concat (path, old, sPath);⓪$ResetList (pcList);⓪$REPEAT ⓪&pc := NextEntry (pcList);⓪$UNTIL (pc = NIL) OR StrEqual (sPath, pc^.oldPath);⓪$IF pc # NIL⓪$THEN⓪&FastStrings.Concat (path, new, sPath);⓪&FastStrings.Assign (sPath, pc^.newPath);⓪$ELSE⓪&ALLOCATE (pc, TSIZE (pcEntry));⓪&IF pc = NIL THEN reportOutOfMemory; RETURN FALSE END;⓪&FastStrings.Concat (path, old, pc^.oldPath);⓪&FastStrings.Concat (path, new, pc^.newPath);⓪&AppendEntry (pcList, pc, voidO);⓪&IF voidO THEN reportOutOfMemory; RETURN FALSE END;⓪$END;⓪$RETURN TRUE⓪"END insertChangeEntry;⓪"⓪"(* %% added 27.6.90 DS *)⓪"PROCEDURE TestAndChange (VAR path : ARRAY OF CHAR;⓪;last : CARDINAL);⓪"(* If path is in the pcList, path will be replaced by the newPath.⓪#* this proc call's itself recursively to change previous changed ⓪#* parts of a path correct.⓪#* 'last' is a control-parameter to pretend infinite loops. (i don't ⓪#* know if it's necessary).⓪#*)⓪%VAR p : INTEGER;⓪)l : CARDINAL;⓪)pc: pcPtr;⓪)tPath : str128;⓪)tName : fileName;⓪"BEGIN⓪$l := Length (path);⓪$IF (l > 2) AND ~(l = last)⓪$THEN⓪&SplitPath (path, tPath, tName);⓪&tPath[Length(tPath)-1] := 0c;     (* '\' löschen *)⓪&TestAndChange (tPath, l);⓪&Append ('\',tPath, voidO);        (* '\' wieder anfügen *)⓪&FastStrings.Concat (tPath, tName, path);⓪&ResetList (pcList);⓪&REPEAT⓪(pc := NextEntry (pcList);⓪&UNTIL (pc = NIL) OR StrEqual (path, pc^.oldPath);⓪&IF pc # NIL⓪&THEN⓪(FastStrings.Assign (pc^.newPath, path);⓪&END;⓪$END;⓪"END TestAndChange;⓪"⓪"PROCEDURE flushOneElem;⓪"⓪$VAR pathChanged : BOOLEAN;⓪"⓪$BEGIN⓪&WITH elem^ DO IF isSubdir THEN⓪&⓪((* %% added by DS 27.6.90: *)⓪(SplitPath (newPath, path, orgFn);⓪(TestAndChange (path, 0);⓪(FastStrings.Concat (path, orgFn, newPath);⓪*⓪(pathChanged := FALSE;⓪(⓪(LOOP⓪*CreateDir (newPath, ioRes);⓪*IF ioRes = fAccessDenied THEN               (*  folder exists  *)⓪*⓪,SplitPath (newPath, path, oldFn);⓪,fn := oldFn;⓪,IF ~ cb^.feAlert (fn) THEN ioRes := fFileExists; EXIT END;⓪,⓪,(* %% added by DS 27.6.90: *)⓪,IF ~StrEqual (oldFn, fn)⓪,THEN ⓪.pathChanged := TRUE⓪,ELSE⓪.ioRes := fFileExists;⓪.EXIT⓪,END;⓪,⓪,FastStrings.Concat (path, fn, newPath);⓪,⓪*ELSE EXIT END;                              (*  success  *)⓪(END;⓪(⓪((* %% added by DS 27.6.90: *)⓪(IF pathChanged THEN⓪+IF ~insertChangeEntry (path, orgFn, fn, cb^.oldPathLen)⓪+THEN stop := TRUE⓪+END;⓪(END;⓪(⓪&ELSE⓪&⓪(IF seekPos > 0L THEN                    (*  append  *)⓪(⓪*Open (f, newPath, writeOnly);⓪*IF stateErr () THEN Remove (f); RETURN END;⓪*Seek (f, seekPos, fromBegin);⓪*IF stateErr () THEN Remove (f); RETURN END;⓪*⓪(ELSE                                    (*  new file  *)⓪*mode := noReplace;⓪*⓪*TestAndChange (newPath, 0);⓪*⓪*LOOP⓪*⓪,Create (f, newPath, writeOnly, mode);⓪,IF State (f) = fFileExists THEN             (*  file exists  *)⓪,⓪.ResetState (f);⓪.SplitPath (newPath, path, oldFn);⓪.fn := oldFn;⓪.IF ~ cb^.feAlert (fn) THEN ioRes := fFileExists; RETURN END;⓪.IF StrEqual (fn, oldFn) THEN mode := replaceOld⓪.ELSE FastStrings.Concat (path, fn, newPath) END;⓪.⓪,ELSIF stateErr () THEN RETURN               (*  file error!  *)⓪,ELSE EXIT END;                              (*  success  *)⓪,⓪*END;⓪*⓪(END;⓪(⓪(WriteBytes (f, start, length);⓪(IF stateErr () THEN Remove (f); RETURN END;⓪(Close (f);⓪(Open (f, newPath, writeOnly);⓪(SetDateTime (f, date, time);⓪((* IF stateErr () THEN Remove (f); RETURN END; *)⓪(Close (f);⓪(⓪&END END;⓪$END flushOneElem;⓪$⓪"BEGIN⓪$elem := cb^.bottom;⓪$LOOP⓪&IF elem^.next = NIL THEN EXIT END;⓪&⓪&flushOneElem;⓪&⓪&doShowStatus (ADR (cb^.status), ioRes, stop);        (*  communicate  *)⓪&IF stop THEN cb^.success := FALSE; EXIT END;⓪&⓪&elem := elem^.next;⓪$END;⓪$⓪$cb^.next := cb^.bottom;             (*  free buffer contens  *)⓪$cb^.next^.next := NIL;⓪"END flushCopyBuffer;⓪"⓪ ⓪ (*  createCopyBufferElem -- Creates a new elem. in the 'copyBuffer', if⓪!*                          there is not enough room to do so, the buffer⓪!*                          is flushed first.⓪!*                          Call only, if there are no open files.⓪!*)⓪ ⓪ PROCEDURE createCopyBufferElem (    cb  : copyBuffer;⓪@VAR elem: copyBufferElem);⓪ ⓪"BEGIN⓪$IF bufAvail (cb) < (minCopySpace DIV 2L) THEN⓪&flushCopyBuffer (cb); IF ~ cb^.success THEN RETURN END;⓪$END;⓪$⓪$WITH cb^ DO⓪&elem := next;⓪&next := copyBufferElem (LONGCARD (bottom) + length - SIZE (cb^.next^));⓪&elem^.next := next;⓪&elem^.next^.next := NIL;          (*  mark next elem as free  *)⓪&elem^.start := ADDRESS (elem) + ADDRESS (SIZE (elem^));⓪&elem^.length := LONGCARD (elem^.next) - LONGCARD (elem^.start);⓪$END;⓪"END createCopyBufferElem;⓪ ⓪ (* deleteCopyBufferElem -- Deletes a 'copyBufferElem'. The element must⓪!*                         be the last in the 'copyBuffer'!⓪!*)⓪ ⓪ PROCEDURE deleteCopyBufferElem (    cb: copyBuffer;⓪@VAR elem: copyBufferElem);⓪ ⓪"BEGIN⓪$cb^.next := elem;⓪$elem^.next := NIL;⓪"END deleteCopyBufferElem;⓪"⓪ (*  shrinkBufferElem -- Reduces the length of 'elem' to 'bytes' byte.⓪!*⓪!*                      ATTENTION: -- Could only be used for the last⓪!*                                    used element of a buffer.⓪!*                                 -- Length of the elem. and start of⓪!*                                    the next differ, if 'bytes' is odd.⓪!*)⓪ ⓪ PROCEDURE shrinkBufferElem (cb   : copyBuffer;⓪<elem : copyBufferElem;⓪<bytes: LONGCARD);⓪ ⓪"BEGIN⓪$(*  if not last used elem. or trying to enlarge elem. size⓪%*)⓪$IF (elem^.next^.next # NIL) OR (elem^.length < bytes) THEN HALT END;⓪$⓪$elem^.length := bytes;⓪$elem^.next := ADDRESS (elem^.start) + ADDRESS (bytes + bytes MOD 2L);⓪$elem^.next^.next := NIL;⓪$cb^.next := elem^.next;⓪"END shrinkBufferElem;⓪"⓪"⓪ PROCEDURE readIntoBuffer (REF path: ARRAY OF CHAR;⓪:VAR pos : LONGCARD;⓪>cb  : copyBuffer);⓪ ⓪"VAR   f        : File;⓪(bufElem  : copyBufferElem;⓪(readBytes: LONGCARD;⓪(success  : BOOLEAN;⓪"⓪"PROCEDURE stateErr (): BOOLEAN;⓪"⓪$BEGIN⓪&cb^.success := (State (f) = fOK);⓪&IF ~ cb^.success THEN⓪(cb^.status.fileErrAlert (State (f));⓪(ResetState (f);⓪(pos := 0L;⓪(Close (f);⓪(bufElem^.next := NIL;⓪&END;⓪&RETURN ~ cb^.success⓪$END stateErr;⓪$⓪ ⓪"BEGIN⓪$⓪$(*  alloc. room in the buffer for the new file (or part of it).⓪%*)⓪%⓪$createCopyBufferElem (cb, bufElem);⓪$IF ~ cb^.success THEN⓪$pos := 0L; RETURN END;⓪$WITH bufElem^ DO⓪&Copy (path, cb^.oldPathLen, Length (path) - cb^.oldPathLen, newPath,⓪,voidO);⓪&Insert (cb^.newPath, 0, newPath, success);⓪&IF ~ success THEN⓪(reportPathFault;⓪(deleteCopyBufferElem (cb, bufElem);⓪(pos := 0L;⓪(RETURN⓪&END;⓪&isSubdir := FALSE;⓪&seekPos := pos;⓪&⓪&Open (f, path, readOnly); IF stateErr () THEN RETURN END;⓪&GetDateTime (f, date, time);⓪&Seek (f, pos, fromBegin); IF stateErr () THEN RETURN END;⓪&ReadBytes (f, start, length, readBytes); IF stateErr () THEN RETURN END;⓪&pos := FilePos (f);⓪&IF pos = FileSize (f) THEN pos := 0L END;         (*  EOF  *)⓪&Close (f);⓪&⓪&shrinkBufferElem (cb, bufElem, readBytes);⓪&⓪$END;⓪"END readIntoBuffer;⓪ ⓪"⓪0(*  proc.s for query through file list  *)⓪0(*  ==================================  *)⓪0⓪0⓪((*  The following proc.s shouldn't directly or indirectly be⓪)*  recursive. Cause the caller is working with global var.s⓪)*)⓪)⓪ TYPE    fileHandleProc      = PROCEDURE (REF (*file: *) ARRAY OF CHAR,⓪I(*env : *) ADDRESS): BOOLEAN;⓪(dirHandleProc       = PROCEDURE (REF (*dir: *) ARRAY OF CHAR,⓪I(*env: *) ADDRESS): BOOLEAN;⓪I⓪(oldPathLenToEnvProc = PROCEDURE ((*oldLen: *) CARDINAL,⓪I(*env   : *) ADDRESS);⓪I⓪(queryEnv        = RECORD⓪<handleFile: fileHandleProc;⓪<handleDir : dirHandleProc;⓪<handleEnv : ADDRESS;⓪<dirFirst  : BOOLEAN;⓪<⓪<stop      : BOOLEAN;⓪<pathChanged : BOOLEAN;⓪<newPath   : PathStr;⓪:END;⓪ ⓪ VAR     dontKnowANameEnv: queryEnv;⓪(dontKnowANameStr: str128;⓪(⓪(⓪ ⓪ PROCEDURE dontKnowAName (REF path: ARRAY OF CHAR; entry: DirEntry): BOOLEAN;⓪ ⓪"VAR   success: BOOLEAN;⓪(ioRes  : INTEGER;⓪((* %% added 30.6.90 DS: because dontKnowAName calls itself recursively⓪)* the following var has to be local. Otherwise some pathes will⓪)* not be set correct! See remark 34 lines above!!⓪)*)⓪(dontKnowANameStr: str128;⓪ ⓪"BEGIN⓪$IF entry.name[0] # '.' THEN WITH dontKnowANameEnv DO⓪$⓪&Concat (path, entry.name, dontKnowANameStr, success);⓪&IF ~ success THEN reportPathFault; stop := TRUE; RETURN FALSE END;⓪&IF isSubdir (entry.attr) THEN⓪&⓪(IF dirFirst THEN⓪*stop := ~ handleDir (dontKnowANameStr, handleEnv);⓪*IF stop THEN RETURN FALSE END;⓪(END;⓪(⓪(Append ('\*.*', dontKnowANameStr, success);⓪(IF ~ success THEN reportPathFault; stop := TRUE; RETURN FALSE END;⓪(DirQuery (dontKnowANameStr, filesAndSubdirs, dontKnowAName, ioRes);⓪(IF stop OR (ioRes # fOK) THEN stop := TRUE; RETURN FALSE END;⓪(⓪(IF ~ dirFirst THEN⓪*Concat (path, entry.name, dontKnowANameStr, success);⓪*stop := ~ handleDir (dontKnowANameStr, handleEnv);⓪*IF stop THEN RETURN FALSE END;⓪(END;⓪(⓪&ELSE stop := ~ handleFile (dontKnowANameStr, handleEnv) END;⓪&⓪&IF stop THEN RETURN FALSE END;⓪&⓪$END END;⓪$⓪$RETURN TRUE⓪"END dontKnowAName;⓪ ⓪ PROCEDURE queryFileList (REF path          : ARRAY OF CHAR;⓪=files         : List;⓪=workOnFile    : fileHandleProc;⓪=workOnDir     : dirHandleProc;⓪=setOldPathLen : oldPathLenToEnvProc;⓪=workEnv       : ADDRESS;⓪=workOnDirFirst: BOOLEAN);⓪ ⓪"VAR   entry  : ptrMaxStr;⓪(str,⓪(str2,⓪(str3   : str128;⓪(ioRes  : INTEGER;⓪(attrs  : FileAttrSet;⓪(success: BOOLEAN;⓪ ⓪"BEGIN⓪$WITH dontKnowANameEnv DO⓪$⓪&handleFile := workOnFile;⓪&handleDir  := workOnDir;⓪&handleEnv  := workEnv;⓪&dirFirst   := workOnDirFirst;⓪&stop := FALSE;⓪&pathChanged := FALSE;⓪&⓪&IF path[0]#0C THEN⓪(IF path [Length (path) - 1] = '\' THEN FastStrings.Assign (path, str3)⓪(ELSE Concat (path, '\', str3, success) END;⓪&ELSE str3 := '' END;⓪&⓪&ResetList (files);⓪&entry := NextEntry (files);⓪&WHILE entry # NIL DO⓪&⓪(FastStrings.Assign (entry^, str2); (*  !!! 'entry^' by reference !!!  *)⓪(⓪(Concat (str3, str2, str, success);⓪(IF ~ success THEN reportPathFault; RETURN END;⓪(⓪(SplitPath (str, str2, voidFN);⓪(setOldPathLen (Length (str2), workEnv);⓪(⓪(GetFileAttr (str, attrs, ioRes); IF ioRes # fOK THEN RETURN END;⓪(IF isSubdir (attrs) THEN⓪(⓪*IF dirFirst THEN⓪,IF ~ handleDir (str, handleEnv) THEN RETURN END⓪*END;⓪*⓪*Concat (str, '\*.*', str2, success);⓪*IF ~ success THEN reportPathFault; RETURN END;⓪*DirQuery (str2, filesAndSubdirs, dontKnowAName, ioRes);⓪*IF stop OR (ioRes # fOK) THEN RETURN END;⓪(⓪*IF ~ dirFirst THEN⓪,IF ~ handleDir (str, handleEnv) THEN RETURN END⓪*END;⓪*⓪(ELSE IF ~ handleFile (str, handleEnv) THEN RETURN END END;⓪(⓪(entry := NextEntry (files);⓪&END;⓪&⓪$END;⓪"END queryFileList;⓪!⓪!⓪ PROCEDURE statusDummy (c: CARDINAL; VAR s: BOOLEAN);⓪ ⓪"BEGIN⓪$s := FALSE;⓪"END statusDummy;⓪ ⓪ PROCEDURE setLenDummy (c: CARDINAL; env: ADDRESS);⓪ ⓪"END setLenDummy;⓪ ⓪ ⓪8(*  proc.s for query  *)⓪8(*  ================  *)⓪ ⓪ PROCEDURE countEntry (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"BEGIN⓪$INC (env^);         (*  not clean, but saves a cast  *)⓪$RETURN TRUE⓪"END countEntry;⓪"⓪ PROCEDURE deleteFile (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR   ioRes: INTEGER;⓪(stop : BOOLEAN;⓪ ⓪"BEGIN⓪$Delete (path, ioRes);⓪$doShowStatus (env, ioRes, stop);⓪$RETURN ~ stop⓪"END deleteFile;⓪"⓪ PROCEDURE deleteDir (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR   ioRes: INTEGER;⓪(stop : BOOLEAN;⓪"⓪"BEGIN⓪$DeleteDir (path, ioRes);⓪$doShowStatus (env, ioRes, stop);⓪$RETURN ~ stop⓪"END deleteDir;⓪ ⓪ ⓪ PROCEDURE fileInBuffer (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR   cb  : copyBuffer;⓪(pos : LONGCARD;⓪ ⓪"BEGIN⓪$cb := copyBuffer (env);⓪$⓪$pos := 0L;⓪$REPEAT⓪&readIntoBuffer (path, pos, cb);⓪$UNTIL pos = 0L;⓪$⓪$RETURN cb^.success⓪"END fileInBuffer;⓪"⓪ PROCEDURE dirInBuffer (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR   cb     : copyBuffer;⓪(bufElem: copyBufferElem;⓪(success: BOOLEAN;⓪(tPath  : str128;⓪(⓪ ⓪"BEGIN⓪$cb := copyBuffer (env);⓪$⓪$createCopyBufferElem (cb, bufElem);⓪$IF ~ cb^.success THEN RETURN FALSE END;⓪$WITH bufElem^ DO⓪&Concat (cb^.newPath,⓪.FuncStrings.DelStr (path, 0, cb^.oldPathLen), tPath, success);⓪&IF ~ success THEN⓪(reportPathFault;⓪(deleteCopyBufferElem (cb, bufElem);⓪(RETURN FALSE⓪&END;⓪&FastStrings.Assign (tPath, newPath);⓪&⓪&isSubdir := TRUE;⓪&⓪$END;⓪$⓪$shrinkBufferElem (cb, bufElem, 0L);⓪$⓪$RETURN TRUE⓪"END dirInBuffer;⓪ ⓪ PROCEDURE setOldPathLen (len: CARDINAL; env: ADDRESS);⓪ ⓪"VAR   cb: copyBuffer;⓪ ⓪"BEGIN⓪$cb := copyBuffer (env);⓪$⓪$cb^.oldPathLen := len;⓪"END setOldPathLen;⓪"⓪"⓪8(*  Die exportierten Routinen  *)⓪8(*  =========================  *)⓪"⓪ PROCEDURE CountFilesAndDirs (REF path: ARRAY OF CHAR;⓪Al   : List;⓪=VAR no  : CARDINAL);⓪ ⓪"BEGIN⓪$no := 0;⓪$queryFileList (path, l, countEntry, countEntry, setLenDummy, ADR (no),⓪3TRUE);⓪"END CountFilesAndDirs;⓪"⓪ PROCEDURE DeleteFiles (REF path        : ARRAY OF CHAR;⓪7files       : List;⓪7noFiles     : CARDINAL;⓪7showStatus  : FileOpStatusProc;⓪7fileErrAlert: FileErrorAlertProc);⓪ ⓪"VAR   status: statusRecord;⓪(stop  : BOOLEAN;⓪ ⓪"BEGIN⓪$showStatus (noFiles, stop); IF stop THEN RETURN END;⓪&⓪$status.fileErrAlert := fileErrAlert;⓪$status.showStatus := showStatus;⓪$status.noFiles := noFiles;⓪$⓪$queryFileList (path, files, deleteFile, deleteDir, setLenDummy,⓪3ADR (status), FALSE);⓪"END DeleteFiles;⓪ ⓪ PROCEDURE CopyFiles (REF path        : ARRAY OF CHAR;⓪5files       : List;⓪5noFiles     : CARDINAL;⓪5REF newPath     : ARRAY OF CHAR;⓪5deleteOld,⓪5useAllMem   : BOOLEAN;⓪5feAlert     : FileExistsAlertProc;⓪5showStatus  : FileOpStatusProc;⓪5fileErrAlert: FileErrorAlertProc);⓪ ⓪"VAR   buffer : copyBuffer;⓪(len    : CARDINAL;⓪(success,⓪(stop   : BOOLEAN;⓪(entry  : pcPtr;⓪ ⓪"BEGIN⓪$showStatus (noFiles, stop); IF stop THEN RETURN END;⓪&⓪$(* %% added 27.6.90 DS *)⓪$CreateList (pcList, success);⓪$IF success (* TRUE means error, but i don't wanted another var *)⓪$THEN reportOutOfMemory; RETURN END;⓪$⓪$createCopyBuffer (buffer, useAllMem, success);⓪$IF ~ success THEN reportOutOfMemory; RETURN END;⓪$buffer^.feAlert := feAlert;⓪$Assign (newPath, buffer^.newPath, success);⓪$len := Length (newPath);⓪$IF ~ success OR (len < 2) THEN⓪&reportPathFault;⓪&deleteCopyBuffer (buffer);⓪&RETURN⓪$END;⓪$IF newPath[len - 1] # '\' THEN Append ('\', buffer^.newPath, voidO) END;⓪$buffer^.status.fileErrAlert := fileErrAlert;⓪$buffer^.status.showStatus := showStatus;⓪$buffer^.status.noFiles := noFiles;⓪$buffer^.success := TRUE;⓪$⓪$queryFileList (path, files, fileInBuffer, dirInBuffer, setOldPathLen,⓪3buffer, TRUE);⓪$flushCopyBuffer (buffer);⓪$⓪$deleteCopyBuffer (buffer);⓪$⓪$(* %% added 27.6.90 DS *)⓪$(* delete pathList *)⓪$ResetList (pcList);⓪$entry := PrevEntry (pcList);⓪$WHILE entry # NIL DO⓪&RemoveEntry (pcList, voidO);⓪&DEALLOCATE (entry, 0L);⓪&entry := CurrentEntry (pcList);⓪$END;⓪$DeleteList (pcList, success)⓪$⓪"END CopyFiles;⓪"⓪ PROCEDURE FileInformation (REF name        : ARRAY OF CHAR;⓪;showFileInfo: FileInfoProc;⓪;fileErrorAlt: FileErrorAlertProc);⓪ ⓪"VAR   entry,⓪(oldEntry: DirEntry;⓪(ioRes   : INTEGER;⓪(path,⓪(newName : str128;⓪(f: File;⓪(success : BOOLEAN;⓪ ⓪"PROCEDURE error (): BOOLEAN;⓪$BEGIN⓪&IF ioRes < fOK THEN fileErrorAlt (ioRes); RETURN TRUE END;⓪&RETURN FALSE⓪$END error;⓪ ⓪"PROCEDURE errorF (): BOOLEAN;⓪$BEGIN⓪&ioRes:= State (f);⓪&RETURN error ()⓪$END errorF;⓪ ⓪"BEGIN⓪$GetDirEntry (name, entry, ioRes);⓪$IF error () THEN RETURN END;⓪$oldEntry := entry;⓪$⓪$showFileInfo (entry);⓪$⓪$SplitPath (name, path, voidFN);⓪$Concat (path, entry.name, newName, success);⓪$IF ~ success THEN reportPathFault; RETURN END;⓪$⓪$IF ~ StrEqual (entry.name, oldEntry.name) THEN⓪&Rename (name, newName, ioRes);⓪&IF error () THEN RETURN END;⓪$END;⓪$IF NOT (subdirAttr IN oldEntry.attr) THEN⓪&IF ~VarEqual (entry.date, oldEntry.date)⓪&OR ~VarEqual (entry.time, oldEntry.time) THEN⓪(Open (f, newName, readOnly);⓪(IF errorF () THEN RETURN END;⓪(SetDateTime (f, entry.date, entry.time);⓪(IF errorF () THEN RETURN END;⓪(Close (f);⓪(IF errorF () THEN RETURN END;⓪&END;⓪&IF (entry.attr # oldEntry.attr) THEN⓪(SetFileAttr (newName, entry.attr, ioRes);⓪(IF error () THEN RETURN END;⓪&END;⓪$END;⓪"END FileInformation;⓪ ⓪ PROCEDURE FormatDisk (    drive          : FormatDrive;⓪:sides,⓪:tracks,⓪:sectorsPerTrack,⓪:interleave     : CARDINAL;⓪:REF name           : ARRAY OF CHAR;⓪:showStatus     : FileOpStatusProc;⓪6VAR result         : FormatResult);⓪ ⓪"CONST fmtBufferSize   = 11L * 1024L;⓪ ⓪"VAR   fmtBuffer       : ADDRESS;⓪"⓪"PROCEDURE write(* (noSectors, side, track, sector: CARDINAL) on the A7 *);⓪3⓪$(*$L-*)⓪$BEGIN⓪&ASSEMBLER⓪(MOVE.L  (A7)+,(A3)+             ; save ret. addr.⓪(⓪(MOVE.W  drive(A6),-(A7)⓪(CLR.L   -(A7)                   ; not used⓪(MOVE.L  fmtBuffer(A6),-(A7)⓪(MOVE.W  #flopwr,-(A7)           ; write the boot sector⓪(TRAP    #xbios⓪(LEA     $14(A7),A7⓪(⓪(MOVE.L  -(A3),-(A7)             ; restore ret. addr.⓪&END;⓪$END write;⓪$(*$L=*)⓪ ⓪"BEGIN⓪$ASSEMBLER⓪(MOVEM.L D4-D6,-(A7)⓪(⓪(SUBQ.W  #1,drive(A6)            ; 'drvA' ist 1⓪(⓪(MOVE.L  result(A6),A0⓪(MOVE.W  #failedFR,(A0)          ; be pessimistic⓪#⓪(;  format media⓪(;⓪(;  D6.W ~ counts tracks | D4.W ~ counts sides⓪(⓪(LEA     fmtBuffer(A6),A0⓪(MOVE.L  A0,(A3)+⓪(MOVE.L  #fmtBufferSize,(A3)+⓪(JSR     ALLOCATE                ; alloc. 'fmtBuffer'⓪(TST.L   fmtBuffer(A6)⓪(BNE     allocOk⓪(⓪(TRAP    #noErrorTrap            ; not enough memory avaible⓪(DC.W    OutOfMemory - $4000⓪(BRA.W   ende⓪ allocOk⓪(⓪(MOVE.W  tracks(A6),D6⓪(SUBQ.W  #1,D6⓪ trackLoop⓪ ⓪(MOVE.W  sides(A6),D4⓪(SUBQ.W  #1,D4⓪ sideLoop⓪ ⓪(MOVE.W  #$E5E5,-(A7)            ; virgin word⓪(MOVE.L  #$87654321,-(A7)        ; magic⓪(MOVE.W  interleave(A6),-(A7)⓪(MOVE.W  D4,-(A7)⓪(MOVE.W  D6,-(A7)⓪(MOVE.W  sectorsPerTrack(A6),-(A7)⓪(MOVE.W  drive(A6),-(A7)⓪(CLR.L   -(A7)                   ; not used⓪(MOVE.L  fmtBuffer(A6),-(A7)⓪(MOVE.W  #flopfmt,-(A7)⓪(TRAP    #xbios                  ; format one track⓪(LEA     $1A(A7),A7⓪(TST.W   D0⓪(BNE.W   stop                    ; bad sectors (no marking yet)⓪ ⓪(DBF     D4,sideLoop⓪(⓪(MOVE.W  D6,(A3)+⓪(SUBQ.W  #2,A7⓪(MOVE.L  A7,(A3)+⓪(MOVE.L  showStatus(A6),A0⓪(JSR     (A0)⓪(TST.W   (A7)+⓪(BNE.W   stop                    ; check user break⓪ ⓪(DBF     D6, trackLoop⓪(⓪(;  write boot sector⓪(⓪(MOVE.L  fmtBuffer(A6),A0⓪(MOVE.W  #127,D0⓪ clr1Loop⓪(CLR.L   (A0)+⓪(DBF     D0,clr1Loop⓪(⓪(CLR.W   -(A7)                   ; not executable⓪(MOVEQ   #1,D0⓪(ADD.W   sides(A6),D0            ; 2 ~ SS, 3 ~ DS⓪(MOVE.W  D0,-(A7)⓪(MOVE.L  #$1000000,-(A7)         ; random serial no.⓪(MOVE.L  fmtBuffer(A6),-(A7)⓪(MOVE.W  #protobt,-(A7)          ; make a boot sector⓪(TRAP    #xbios⓪(LEA     $E(A7),A7⓪(⓪(MOVE.W  #1,-(A7)                ; one sector⓪(CLR.W   -(A7)                   ; side 1⓪(CLR.W   -(A7)                   ; track 0⓪(MOVE.W  #1,-(A7)                ; sector 1⓪(BSR     write                   ; write boot sector⓪(TST.W   D0⓪(BNE.W   stop                    ; stop, if write err⓪(⓪(;  write FATs⓪(⓪(MOVE.L  fmtBuffer(A6),A0⓪(MOVE.W  #895,D0                 ; clear 7 sectors⓪ clr2Loop⓪(CLR.L   (A0)+⓪(DBF     D0,clr2Loop⓪(MOVE.L  fmtBuffer(A6),A0⓪(MOVE.L  #$F7FFFF00,(A0)         ; FAT-start must be $F7 FF FF⓪(⓪(MOVE.W  #5,-(A7)                ; 5 sectors⓪(CLR.W   -(A7)                   ; side 1⓪(CLR.W   -(A7)                   ; track 0⓪(MOVE.W  #2,-(A7)                ; sector 2⓪(BSR     write                   ; write FAT 1⓪(TST.W   D0⓪(BNE.W   stop                    ; stop, if write err⓪(⓪(MOVEQ   #5,D6                   ; 5 sectors⓪(MOVE.W  sectorsPerTrack(A6),D4⓪(SUBQ.W  #6,D4                   ; 'sectorsPerTrack' - alreadyUsed -> D4⓪(SUB.W   D4,D6                   ; remaining sectors -> D6⓪(⓪(MOVE.W  D4,-(A7)                ; x sectors⓪(CLR.W   -(A7)                   ; side 1⓪(CLR.W   -(A7)                   ; track 0⓪(MOVE.W  #7,-(A7)                ; sector 7⓪(BSR     write                   ; write FAT 2 Part 1⓪(TST.W   D0⓪(BNE     stop                    ; stop, if write err⓪(⓪(MOVE.W  sides(A6),D0            ; if two sides then⓪(MOVEQ   #1,D5                   ;   side 2, track 0⓪(SUB.W   D5,D0                   ; else⓪(SUB.W   D0,D5                   ;   side 1, track 1⓪(EXG.L   D0,D4                   ; D4 = side, D5 = track⓪(⓪(TST.W   D6⓪(BEQ     noPart2                 ; jump, if no sectors left⓪(⓪(MOVE.W  D6,-(A7)⓪(MOVE.W  D4,-(A7)⓪(MOVE.W  D5,-(A7)⓪(MOVE.W  #1,-(A7)                ; sector 1⓪(MOVE.W  drive(A6),-(A7)⓪(CLR.L   -(A7)                   ; not used⓪(MULU    #512,D0⓪(ADD.L   fmtBuffer(A6),D0⓪(MOVE.L  D0,-(A7)                ; alreadyWrittenSecs * 512 + 'fmtBuffer'⓪(MOVE.W  #flopwr,-(A7)           ; write the boot sector⓪(TRAP    #xbios⓪(LEA     $14(A7),A7⓪(TST.W   D0⓪(BNE     stop                    ; stop, if write err⓪(⓪ noPart2⓪ ⓪(;  write root directory⓪(⓪(MOVE.L  fmtBuffer(A6),A0⓪(MOVE.L  name(A6),A1             ; ADR (name) -> A1⓪(MOVE.W  name+4(A6),D1           ; HIGH (name) -> D1⓪(MOVEQ   #11,D0⓪(⓪(BRA     nameStart⓪ nameLoop⓪(MOVE.B  D2,(A0)+⓪(SUBQ.W  #1,D1⓪(BMI     nameSpaces⓪ nameStart⓪(MOVE.B  (A1)+,D2⓪(DBEQ    D0,nameLoop⓪(BNE     nameOk⓪(⓪ nameSpaces⓪(BRA     nameSpcStart⓪ nameSpcLoop⓪(MOVE.B  #' ',(A0)+⓪ nameSpcStart⓪(DBF     D0,nameSpcLoop⓪(⓪ nameOk⓪(MOVE.B  #08,(A0)+               ;  attribute set for volume label⓪(⓪(MOVE.W  #7,-(A7)                ; directory length = 7 sectors⓪(MOVE.W  D4,-(A7)⓪(MOVE.W  D5,-(A7)⓪(ADDQ.W  #1,D6⓪(MOVE.W  D6,-(A7)⓪(BSR     write                   ; write directory⓪(TST.W   D0⓪(BNE     stop                    ; stop, if write err⓪(⓪(MOVE.L  result(A6),A0⓪(MOVE.W  #okFR,(A0)              ; flag success!⓪(⓪ stop⓪(LEA     fmtBuffer(A6),A0⓪(MOVE.L  A0,(A3)+⓪(CLR.L   (A3)+⓪(JSR     DEALLOCATE              ; dealloc. 'fmtBuffer'⓪ ende⓪(MOVEM.L (A7)+,D4-D6⓪$END;⓪"END FormatDisk;⓪"⓪ END FileManagement.⓪ ə
  2. (* $FFEA89F2$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$00006B12$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96Ç$00000A48T.......T.......T.......T.......T.......T.......T.......T.......T.......T.......$00000933$0000093E$0000094B$00000168$0000094B$000009B7$00006A40$00007088$000071F9$000071CE$00000933$00000A4B$000009C2$000009D2$00000A48$00006E6D¶Çâ*)
  3.